﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
/*

 */
namespace Single
{
    //例子都通过读取配置文件来实现

    #region 懒汉 第一种,非线程安全的 
    //第一种,非线程安全的
    // Bad code! Do not use!
    //单线程的时候没有问题,但多个线程同事访问的时候就可能同事创建多个实例，而且这多个实例不是同一个对象，虽然后面创建的实例会覆盖先创建的实例，但是还是会存在拿到不同对象的情况。
    public sealed class SingletonFirst
    {
        private static CustomConfig _instance = null;
        public static CustomConfig Instance
        {
            get
            {
                if (_instance != null) return _instance;
                _instance = new CustomConfig();
                return _instance;
            }
        }

        private SingletonFirst()//禁止外部实例化
        {
        }
    }
    #endregion

    #region 懒汉 第二种,简单线程安全
    //没有使用双重检查,多线程下可能会造成不必要的资源浪费
    // Bad code! Do not use!
    public sealed class SingletonSecond
    {
        private static CustomConfig _instance = null;
        private static readonly object PadLock = new object();
        public static CustomConfig Instance
        {
            get
            {
                lock (PadLock)
                {
                    if (_instance != null) return _instance;
                    _instance = new CustomConfig();
                    return _instance;
                }
            }
        }
        private SingletonSecond()//禁止外部实例化
        {
        }
    }
    #endregion


    #region 懒汉 第三种,第二种的升级方式  尝试线程安全（锁前后双重检查）（推荐使用）
    //我们常用的方法就是这种方式了
    //优点 资源利用率高,不使用的时候就不会创建实例,可以执行该类的其他静态方法
    //缺点 多线程的时候不必要的同步开销变大
    public sealed class SingletonThird
    {
        private static CustomConfig _instance = null;
        private static readonly object PadLock = new object();
        public static CustomConfig GetInstance()
        {
            if (_instance != null) return _instance;//这里检查是避免资源浪费,实例不存在才进入同步模块
            {
                lock (PadLock)
                {
                    if (_instance != null) return _instance;//同步模块再检查一次,如果不存在,就只需要同步创建一次
                    _instance = new CustomConfig();
                    _instance.EmailUserName = System.Configuration.ConfigurationManager.AppSettings["EmailUserName"];
                    _instance.EmailPassword = System.Configuration.ConfigurationManager.AppSettings["EmailPassword"];
                    _instance.EmailContentModel = System.Configuration.ConfigurationManager.AppSettings["EmailContentModel"];
                    return _instance;
                }
            }
        }
        private SingletonThird()//禁止外部实例化
        {
        }
    }
    #endregion

    #region 饿汉 第四种,不完全Lazy,但是线程安全且不使用锁
    //Bad code! do not  use
    //基于classloder机制避免了多线程的同步问题
    //优点：线程安全；在类加载好的同时就已经创建好一个静态对象,调用时反映速度快
    //缺点：资源效率不高，可能getInstance()永远不会执行到，但执行该类的其他静态方法或者加载了该类（class.forName)，那么这个实例仍然初始化 
    public sealed class SingletonFourth_1
    {
        private static readonly CustomConfig Instance = new CustomConfig();
        public static CustomConfig GetInstance()
        {
            return Instance;
        }
        private SingletonFourth_1()//禁止实例化
        {
        }
    }

    #region 饿汉变种写法 其实和上面差不多
    //饿汉变种写法 其实和上面差不多
    public sealed class SingletonFourth_2
    {
        private static readonly CustomConfig Instance = null;
        static SingletonFourth_2()
        {
            Instance = new CustomConfig();
        }
        private SingletonFourth_2() { }//禁止外部实例化
        public static CustomConfig GetInstance()
        {
            return Instance;
        }
    }
    #endregion
    #endregion

    #region 懒汉  第五种 静态内部类(推荐使用)

    /*这种方式同样是利用了静态内部类机制保证初始化instance时只有一个线程
     *与第三和第四种不同的地方是在于 这种方式适用了一个静态内部类来加载Instance。第三第四种是只要类被装载了,Instance就实例化了
     *，而这种方式即使类被装载了，只要不调用GetInstance()方法就不会实例化Instance。
     * 想象一下，如果实例化instance很消耗资源，我想让他延迟加载，
     * 另外一方面，我不希望在Singleton类加载时就实例化，因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载，
     * 那么这个时候实例化instance显然是不合适的。这个时候，这种方式相比第三和第四种方式就显得很合理。
    */
    public sealed class SingletonFifth
    {
        private static class Inside
        {
            internal static readonly CustomConfig Instance = new CustomConfig()
            {
                EmailUserName = System.Configuration.ConfigurationManager.AppSettings["EmailUserName"],
                EmailPassword = System.Configuration.ConfigurationManager.AppSettings["EmailPassword"],
                EmailContentModel = System.Configuration.ConfigurationManager.AppSettings["EmailContentModel"]
            };
        }
        public static CustomConfig GetInstance() { return Inside.Instance; }
        private SingletonFifth()//禁止外部实例化
        {
        }
    }
    #endregion

    #region 第六种 使用 .NET 4's Lazy<T> type（推荐使用）
    // Lazy<T>是.NET 4.0中新增的类，它提供了线程安全的延迟加载的调用。
    public sealed class SingletonSixth
    {
        private static readonly Lazy<CustomConfig> Lazy =
            new Lazy<CustomConfig>(() => new CustomConfig()
            {
                EmailUserName = System.Configuration.ConfigurationManager.AppSettings["EmailUserName"],
                EmailPassword = System.Configuration.ConfigurationManager.AppSettings["EmailPassword"],
                EmailContentModel = System.Configuration.ConfigurationManager.AppSettings["EmailContentModel"]
            });

        public static CustomConfig GetInstance()
        {
            return Lazy.Value;
        }
        private SingletonSixth()//禁止外部实例化
        {
        }
    }
    #endregion


    //java里由于枚举和c#不同，可以使用枚举实现单利模式
}
